Skip to content

Fix consensus_tree segfault on arm64 by implementing dynamic stack/heap allocation#243

Merged
ms609 merged 19 commits intomainfrom
copilot/update-clustertable-logic
Feb 5, 2026
Merged

Fix consensus_tree segfault on arm64 by implementing dynamic stack/heap allocation#243
ms609 merged 19 commits intomainfrom
copilot/update-clustertable-logic

Conversation

Copy link
Contributor

Copilot AI commented Feb 4, 2026

Plan to Fix Consensus Tree Hard-coded Leaf Limit

  • Analyze current code to identify all fixed-size allocations
  • Define threshold for switching from stack to heap allocation (8192 leaves)
  • Modify ClusterTable.h to support dynamic Xswitch allocation:
    • Replace std::bitset<ct_max_leaves + 1> with DynamicBitset
    • Use std::bitset for small trees (stack)
    • Use std::vector<unsigned char> for large trees (heap)
  • Modify consensus.cpp to support dynamic S allocation:
    • Keep std::array for small trees (stack)
    • Use std::vector for large trees (heap)
    • Create template function to work with both
  • Add proper error handling for extremely large trees (100000 limit)
  • Update error messages to be more descriptive
  • Update test-consensus.R expectations
  • Update test-ClusterTable.R expectations
  • Test with small trees to ensure performance unchanged
  • Test with large trees (e.g., 33333 leaves) to verify heap allocation
  • Run full test suite to ensure no regressions
  • Fix constexpr ODR issues for TreeDist compatibility
  • Use inline constexpr for cross-platform compatibility (Windows/macOS)

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 4 commits February 4, 2026 13:14
- Add stack threshold (8192) and heap limit (100000) constants
- Create DynamicBitset class for Xswitch with stack/heap allocation
- Template consensus_tree_impl to handle both array and vector S
- Update error messages with specific limits
- Update tests for new limits and add heap allocation tests

Co-authored-by: ms609 <1695515+ms609@users.noreply.github.com>
Co-authored-by: ms609 <1695515+ms609@users.noreply.github.com>
Co-authored-by: ms609 <1695515+ms609@users.noreply.github.com>
Co-authored-by: ms609 <1695515+ms609@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor consensus_tree logic for dynamic tree sizes Fix consensus_tree segfault on arm64 by implementing dynamic stack/heap allocation Feb 4, 2026
Copilot AI requested a review from ms609 February 4, 2026 13:25
@github-actions
Copy link

github-actions bot commented Feb 4, 2026

⚠️ This benchmark result is outdated. See the latest comment below.

Performance benchmark results

Call Status Change Time (ms)
as.Splits(bigTrees) ⚪ NSD -5.4% 22.6 →
24.3, 23.7
as.Splits(someTrees) ⚪ NSD 0.74% 11.2 →
11, 11.2
Consensus(forest1k.888, check = FALSE) ⚪ NSD -2.78% 94.8 →
96.1, 97.9
Consensus(forest201.80, check = FALSE) ⚪ NSD -2.94% 3.98 →
4.09, 4.11
Consensus(forest21.260, 0.5, FALSE) 🟣 ~same -4.07% 1.19 →
1.24, 1.25
Consensus(forest21.260) 🟣 ~same -3.53% 1.19 →
1.23, 1.24
Consensus(forestMaj, 0.5, FALSE) ⚪ NSD -2.03% 2.92 →
2.95, 2.99
DropTip(tr2000, 5) ⚪ NSD 0.17% 20 →
19.7, 20
DropTip(tr80, 5) ⚪ NSD 1.24% 0.105 →
0.103, 0.104
DropTip(unlen2k, 5) ⚪ NSD 0.17% 0.21 →
0.209, 0.211
DropTip(unlen80, 5) ⚪ NSD -0.5% 0.0402 →
0.04, 0.0407
lapply(bigSplits, as.phylo) ⚪ NSD 0.31% 30.5 →
30.5, 30.2
lapply(someSplits, as.phylo) ⚪ NSD 0.57% 14 →
13.9, 13.9
PathLengths(tr2000, full = TRUE) ⚪ NSD 0.23% 19.2 →
19.3, 18.9
PathLengths(tr80, full = TRUE) ⚪ NSD -0.17% 0.104 →
0.104, 0.105
PathLengths(tr80Unif, full = TRUE) ⚪ NSD 68.95% 0.107 →
0.106, 0.0326
RootTree(tr2000, 5) ⚪ NSD -4.59% 0.369 →
0.376, 0.392
RootTree(tr80, c("t3", "t36")) ⚪ NSD -0.83% 0.069 →
0.0703, 0.0686
RootTree(tr80, "t3") ⚪ NSD -0.86% 0.0491 →
0.0494, 0.0496
RootTree(tr80, "t30") ⚪ NSD -0.45% 0.0493 →
0.0497, 0.0494
RootTree(unlen2k, 5) ⚪ NSD -0.7% 0.331 →
0.336, 0.329
RootTree(unlen80, c("t3", "t36")) ⚪ NSD -1.95% 0.0627 →
0.0642, 0.0636
RootTree(unlen80, "t3") ⚪ NSD 0.07% 0.0428 →
0.043, 0.0426
RootTree(unlen80, "t30") ⚪ NSD -0.05% 0.043 →
0.0434, 0.0425
TreeDist::RobinsonFoulds(forest201.80) ⚪ NSD -2.29% 14.9 →
15.1, 15.3
TreeDist::RobinsonFoulds(forest21.888) ⚪ NSD -3.7% 3.12 →
3.15, 3.26
TreeTools:::path_lengths(tr80$edge, tr80$edge.length, FALSE) ⚪ NSD -0.03% 0.0925 →
0.0921, 0.0929
TreeTools:::postorder_order(bal40) ⚪ NSD -0.61% 0.00165 →
0.00166, 0.00167
TreeTools:::postorder_order(bal40k) ⚪ NSD -0.75% 0.441 →
0.442, 0.446
TreeTools:::postorder_order(dbal40) ⚪ NSD -0.65% 0.00171 →
0.00172, 0.00174
TreeTools:::postorder_order(dbal40k) ⚪ NSD 0.47% 2.14 →
2.12, 2.14
TreeTools:::postorder_order(dpec40) ⚪ NSD -3.18% 0.00252 →
0.00255, 0.00281
TreeTools:::postorder_order(dpec40k) 🟣 ~same 3.94% 3420 →
3290, 3290
TreeTools:::postorder_order(drnd80) ⚪ NSD -1.03% 0.00398 →
0.00396, 0.00413
TreeTools:::postorder_order(nbal40) ⚪ NSD -2.91% 0.00206 →
0.00209, 0.00217
TreeTools:::postorder_order(nbal40k) ⚪ NSD 0.85% 2.19 →
2.16, 2.18
TreeTools:::postorder_order(npec40) ⚪ NSD -2.45% 0.00282 →
0.00284, 0.00312
TreeTools:::postorder_order(npec40k) 🟣 ~same 3.72% 3440 →
3310, 3310
TreeTools:::postorder_order(nrnd80) ⚪ NSD -1.32% 0.00453 →
0.00457, 0.00461
TreeTools:::postorder_order(pec40) ⚪ NSD -9.07% 0.00165 →
0.00165, 0.00195
TreeTools:::postorder_order(pec40k) ⚪ NSD 1.71% 0.435 →
0.428, 0.427
TreeTools:::postorder_order(rnd80) ⚪ NSD -2.91% 0.00209 →
0.00208, 0.0023

@github-actions
Copy link

github-actions bot commented Feb 4, 2026

⚠️ This benchmark result is outdated. See the latest comment below.

Performance benchmark results

Call Status Change Time (ms)
as.Splits(bigTrees) ⚪ NSD 0.72% 24.2 →
23.2, 24.7
as.Splits(someTrees) ⚪ NSD 1.38% 12.2 →
11.8, 12.2
Consensus(forest1k.888, check = FALSE) ⚪ NSD 3.24% 105 →
101, 103
Consensus(forest201.80, check = FALSE) ⚪ NSD 5.72% 4.47 →
4.21, 4.23
Consensus(forest21.260, 0.5, FALSE) ⚪ NSD -0.84% 1.24 →
1.25, 1.26
Consensus(forest21.260) ⚪ NSD -0.98% 1.23 →
1.25, 1.25
Consensus(forestMaj, 0.5, FALSE) ⚪ NSD -0.97% 3.07 →
3.06, 3.13
DropTip(tr2000, 5) 🟣 ~same 4.37% 22.2 →
20.9, 21.4
DropTip(tr80, 5) ⚪ NSD 0.2% 0.108 →
0.108, 0.108
DropTip(unlen2k, 5) ⚪ NSD -1.81% 0.212 →
0.213, 0.221
DropTip(unlen80, 5) ⚪ NSD 0.12% 0.0413 →
0.0411, 0.0414
lapply(bigSplits, as.phylo) ⚪ NSD -0.03% 31 →
30.9, 31.2
lapply(someSplits, as.phylo) ⚪ NSD 1.97% 14.8 →
14.6, 14.2
PathLengths(tr2000, full = TRUE) ⚪ NSD -0.12% 21 →
19.9, 21.4
PathLengths(tr80, full = TRUE) 🟢 Faster! 71.91% 0.105 →
0.0294, 0.0302
PathLengths(tr80Unif, full = TRUE) 🟢 Faster! 70.75% 0.107 →
0.0312, 0.0315
RootTree(tr2000, 5) ⚪ NSD 0.85% 0.384 →
0.379, 0.382
RootTree(tr80, c("t3", "t36")) ⚪ NSD 0.24% 0.0714 →
0.0712, 0.0712
RootTree(tr80, "t3") ⚪ NSD 0.69% 0.0509 →
0.0505, 0.0505
RootTree(tr80, "t30") ⚪ NSD 1.73% 0.0515 →
0.0506, 0.0505
RootTree(unlen2k, 5) ⚪ NSD 0.87% 0.342 →
0.339, 0.339
RootTree(unlen80, c("t3", "t36")) ⚪ NSD 0.41% 0.0666 →
0.0662, 0.0666
RootTree(unlen80, "t3") ⚪ NSD 2.15% 0.0452 →
0.0439, 0.0445
RootTree(unlen80, "t30") ⚪ NSD 1.92% 0.0455 →
0.0443, 0.0449
TreeDist::RobinsonFoulds(forest201.80) ⚪ NSD -2.83% 16.2 →
16.7, 16.8
TreeDist::RobinsonFoulds(forest21.888) ⚪ NSD -0.33% 3.32 →
3.23, 3.37
TreeTools:::path_lengths(tr80$edge, tr80$edge.length, FALSE) ⚪ NSD 3.9% 0.0945 →
0.0913, 0.0904
TreeTools:::postorder_order(bal40) ⚪ NSD -2.42% 0.00165 →
0.00168, 0.0017
TreeTools:::postorder_order(bal40k) ⚪ NSD -0.56% 0.443 →
0.445, 0.446
TreeTools:::postorder_order(dbal40) ⚪ NSD -1.73% 0.00173 →
0.00173, 0.00179
TreeTools:::postorder_order(dbal40k) ⚪ NSD 1.03% 2.16 →
2.13, 2.14
TreeTools:::postorder_order(dpec40) ⚪ NSD -0.8% 0.00252 →
0.00252, 0.00256
TreeTools:::postorder_order(dpec40k) 🟣 ~same 1.68% 3350 →
3300, 3290
TreeTools:::postorder_order(drnd80) ⚪ NSD -1.52% 0.00396 →
0.00402, 0.00403
TreeTools:::postorder_order(nbal40) ⚪ NSD -1.9% 0.0021 →
0.0021, 0.00218
TreeTools:::postorder_order(nbal40k) ⚪ NSD 0.65% 2.2 →
2.17, 2.2
TreeTools:::postorder_order(npec40) ⚪ NSD 0.03% 0.00284 →
0.00283, 0.00285
TreeTools:::postorder_order(npec40k) 🟣 ~same 2.53% 3410 →
3320, 3320
TreeTools:::postorder_order(nrnd80) ⚪ NSD -0.43% 0.00459 →
0.0046, 0.00461
TreeTools:::postorder_order(pec40) ⚪ NSD 0.06% 0.00167 →
0.00165, 0.0017
TreeTools:::postorder_order(pec40k) ⚪ NSD -0.48% 0.435 →
0.438, 0.437
TreeTools:::postorder_order(rnd80) ⚪ NSD 2.36% 0.00212 →
0.00203, 0.00213

@github-actions
Copy link

github-actions bot commented Feb 4, 2026

⚠️ This benchmark result is outdated. See the latest comment below.

Performance benchmark results

Call Status Change Time (ms)
as.Splits(bigTrees) ⚪ NSD 1.19% 23.7 →
24, 22.2
as.Splits(someTrees) ⚪ NSD -2.53% 11.1 →
11.4, 11.3
Consensus(forest1k.888, check = FALSE) 🟠 Slower 🙁 -6.38% 95.1 →
101, 102
Consensus(forest201.80, check = FALSE) ⚪ NSD -2.8% 4.01 →
4.16, 4.09
Consensus(forest21.260, 0.5, FALSE) 🟣 ~same -4.1% 1.2 →
1.25, 1.25
Consensus(forest21.260) 🟣 ~same -3.97% 1.19 →
1.24, 1.24
Consensus(forestMaj, 0.5, FALSE) ⚪ NSD -1.66% 2.95 →
3, 2.99
DropTip(tr2000, 5) ⚪ NSD 0.38% 20.6 →
20.4, 20.7
DropTip(tr80, 5) ⚪ NSD -1.25% 0.104 →
0.106, 0.104
DropTip(unlen2k, 5) 🟢 Faster! 23.94% 0.277 →
0.208, 0.217
DropTip(unlen80, 5) ⚪ NSD -0.93% 0.0401 →
0.0408, 0.04
lapply(bigSplits, as.phylo) 🟣 ~same 1.91% 30.9 →
30.2, 30.3
lapply(someSplits, as.phylo) ⚪ NSD -0.99% 13.9 →
14.1, 13.9
PathLengths(tr2000, full = TRUE) ⚪ NSD 0.41% 20 →
20, 19.8
PathLengths(tr80, full = TRUE) ⚪ NSD -0.21% 0.102 →
0.102, 0.103
PathLengths(tr80Unif, full = TRUE) 🟢 Faster! 69.82% 0.102 →
0.0301, 0.0313
RootTree(tr2000, 5) ⚪ NSD -3.49% 0.374 →
0.395, 0.374
RootTree(tr80, c("t3", "t36")) ⚪ NSD 0.94% 0.0701 →
0.0697, 0.0692
RootTree(tr80, "t3") ⚪ NSD -1.33% 0.0492 →
0.0502, 0.0493
RootTree(tr80, "t30") ⚪ NSD -0.44% 0.0496 →
0.0501, 0.0494
RootTree(unlen2k, 5) ⚪ NSD 0% 0.334 →
0.332, 0.337
RootTree(unlen80, c("t3", "t36")) ⚪ NSD 0.06% 0.0648 →
0.0653, 0.0641
RootTree(unlen80, "t3") ⚪ NSD -1.15% 0.0428 →
0.0435, 0.043
RootTree(unlen80, "t30") ⚪ NSD -0.49% 0.0433 →
0.044, 0.043
TreeDist::RobinsonFoulds(forest201.80) ⚪ NSD -5.09% 14.9 →
15.4, 16.3
TreeDist::RobinsonFoulds(forest21.888) ⚪ NSD -3.93% 3.14 →
3.26, 3.27
TreeTools:::path_lengths(tr80$edge, tr80$edge.length, FALSE) ⚪ NSD 0.29% 0.0913 →
0.0908, 0.0912
TreeTools:::postorder_order(bal40) ⚪ NSD -3.1% 0.00161 →
0.00167, 0.00164
TreeTools:::postorder_order(bal40k) ⚪ NSD -0.56% 0.44 →
0.445, 0.441
TreeTools:::postorder_order(dbal40) ⚪ NSD -1.75% 0.00171 →
0.00174, 0.00173
TreeTools:::postorder_order(dbal40k) ⚪ NSD 1.07% 2.14 →
2.1, 2.13
TreeTools:::postorder_order(dpec40) ⚪ NSD -0.79% 0.00252 →
0.00254, 0.00254
TreeTools:::postorder_order(dpec40k) 🟣 ~same 2.12% 3360 →
3280, 3290
TreeTools:::postorder_order(drnd80) ⚪ NSD -1.24% 0.00396 →
0.004, 0.00401
TreeTools:::postorder_order(nbal40) ⚪ NSD -0.97% 0.00206 →
0.00209, 0.00208
TreeTools:::postorder_order(nbal40k) ⚪ NSD 1.34% 2.19 →
2.16, 2.16
TreeTools:::postorder_order(npec40) ⚪ NSD -1.39% 0.00281 →
0.00284, 0.00284
TreeTools:::postorder_order(npec40k) 🟣 ~same 3.54% 3440 →
3310, 3320
TreeTools:::postorder_order(nrnd80) ⚪ NSD -0.44% 0.00454 →
0.00454, 0.00458
TreeTools:::postorder_order(pec40) ⚪ NSD 0.61% 0.00165 →
0.00165, 0.00163
TreeTools:::postorder_order(pec40k) ⚪ NSD -0.33% 0.434 →
0.435, 0.435
TreeTools:::postorder_order(rnd80) ⚪ NSD 0.48% 0.00207 →
0.00205, 0.00208

@ms609 ms609 marked this pull request as ready for review February 4, 2026 16:50
@ms609
Copy link
Owner

ms609 commented Feb 4, 2026

@copilot Good start thank you; I had to make some improvements to get this going.

Now I'm seeing:

Failure (test-ClusterTable.R:140:3): ClusterTable with complex trees
Expected `as.numeric(RobinsonFoulds(r4))` to equal `c(8, 0, 8, 8, 0, 8)`.
Differences:
  `actual`: 8.0 8.0 8.0 8.0 8.0 8.0
`expected`: 8.0 0.0 8.0 8.0 0.0 8.0

Here's the test that's triggering it.
I never did understand why the script was working with const but not constexpr. Perhaps you can look into this. The TreeDist source is available in the ms609/TreeDist GitHub repo, or via CRAN; let me know if you need specific files copying here.

test_that("ClusterTable with complex trees", {
  skip_if_not_installed("TreeDist", "2.9.2.9000")
  library("TreeDist")
  
  # Test exposes failures in C++ - constexpr not playing nicely with Rcpp
  # Specifically if replacing
  # const int16 L_COL = int16(0);
  # const int16 R_COL = int16(1);
  # const int16 X_COLS = int16(2);
  # hard-coding, using enum all fails.
  tr1 <- structure(list(
    edge = structure(c(8L, 8L, 9L, 10L, 10L, 9L, 11L, 11L, 8L, 12L, 12L,
                       1L, 9L, 10L, 2L, 3L, 11L, 4L, 5L, 12L, 6L, 7L),
                     dim = c(11L, 2L)),
    Nnode = 5L, tip.label = c("t1", "t2", "t3", "t4", "t5", "t6", "t7")),
    class = "phylo", order = "preorder")
  tr2 <- structure(list(
    edge = structure(c(8L, 9L, 10L, 10L, 9L, 11L, 11L, 8L, 12L, 12L, 8L,
                       9L, 10L, 1L, 2L, 11L, 3L, 4L, 12L, 5L, 6L, 7L),
                     dim = c(11L, 2L)),
    Nnode = 5L, tip.label = c("t1", "t2", "t3", "t4", "t5", "t6", "t7")),
    class = "phylo", order = "preorder")
  t4 <- list(a = tr1, b = tr2, c = tr1, d = tr2)
  r4 <- RootTree(t4, 1)
  
  expect_equal(as.numeric(RobinsonFoulds(r4)), c(8, 0, 8, 8, 0, 8))
})

@github-actions
Copy link

github-actions bot commented Feb 4, 2026

⚠️ This benchmark result is outdated. See the latest comment below.

Performance benchmark results

Call Status Change Time (ms)
as.Splits(bigTrees) ⚪ NSD -8.8% 20.5 →
22.4, 22.3
as.Splits(someTrees) ⚪ NSD -5.94% 11.2 →
11.2, 12
Consensus(forest1k.888, check = FALSE) ⚪ NSD -0.45% 97.8 →
97.2, 99
Consensus(forest201.80, check = FALSE) ⚪ NSD -1.23% 4.06 →
4.07, 4.17
Consensus(forest21.260, 0.5, FALSE) ⚪ NSD -1.09% 1.21 →
1.22, 1.23
Consensus(forest21.260) ⚪ NSD -2.18% 1.2 →
1.22, 1.24
Consensus(forestMaj, 0.5, FALSE) ⚪ NSD -1.31% 3 →
2.98, 3.06
DropTip(tr2000, 5) ⚪ NSD -1.56% 20.1 →
20.1, 20.5
DropTip(tr80, 5) ⚪ NSD -0.7% 0.104 →
0.104, 0.105
DropTip(unlen2k, 5) ⚪ NSD 3.51% 0.218 →
0.209, 0.211
DropTip(unlen80, 5) ⚪ NSD 0.64% 0.0405 →
0.0401, 0.0402
lapply(bigSplits, as.phylo) 🟣 ~same 2.62% 31.5 →
30.8, 30.7
lapply(someSplits, as.phylo) ⚪ NSD -3.1% 14.2 →
14.2, 14.7
PathLengths(tr2000, full = TRUE) ⚪ NSD 0.97% 20.1 →
20.6, 19.1
PathLengths(tr80, full = TRUE) ⚪ NSD 18.08% 0.0373 →
0.0311, 0.0293
PathLengths(tr80Unif, full = TRUE) ⚪ NSD 10.45% 0.0357 →
0.033, 0.0306
RootTree(tr2000, 5) ⚪ NSD -5.16% 0.376 →
0.393, 0.399
RootTree(tr80, c("t3", "t36")) ⚪ NSD -1.22% 0.0704 →
0.0699, 0.0722
RootTree(tr80, "t3") ⚪ NSD -2.71% 0.0495 →
0.0499, 0.0516
RootTree(tr80, "t30") ⚪ NSD -2.67% 0.0495 →
0.05, 0.0515
RootTree(unlen2k, 5) ⚪ NSD 0.3% 0.333 →
0.329, 0.335
RootTree(unlen80, c("t3", "t36")) ⚪ NSD -0.85% 0.0651 →
0.0645, 0.0665
RootTree(unlen80, "t3") ⚪ NSD -0.7% 0.0433 →
0.0428, 0.0442
RootTree(unlen80, "t30") ⚪ NSD -1.09% 0.0436 →
0.0432, 0.0447
TreeDist::RobinsonFoulds(forest201.80) ⚪ NSD -7.6% 15.3 →
16.6, 16.3
TreeDist::RobinsonFoulds(forest21.888) ⚪ NSD -4.14% 3.15 →
3.25, 3.3
TreeTools:::path_lengths(tr80$edge, tr80$edge.length, FALSE) ⚪ NSD 1.9% 0.0944 →
0.0933, 0.0921
TreeTools:::postorder_order(bal40) ⚪ NSD -0.61% 0.00163 →
0.00163, 0.00166
TreeTools:::postorder_order(bal40k) ⚪ NSD -0.64% 0.438 →
0.44, 0.442
TreeTools:::postorder_order(dbal40) ⚪ NSD -5.93% 0.0017 →
0.00185, 0.00174
TreeTools:::postorder_order(dbal40k) ⚪ NSD -1.3% 2.11 →
2.13, 2.14
TreeTools:::postorder_order(dpec40) 🟣 ~same -3.99% 0.00251 →
0.00254, 0.00263
TreeTools:::postorder_order(dpec40k) ⚪ NSD 0.78% 3430 →
3420, 3360
TreeTools:::postorder_order(drnd80) ⚪ NSD -0.53% 0.00397 →
0.00396, 0.00402
TreeTools:::postorder_order(nbal40) ⚪ NSD -4.86% 0.00206 →
0.0022, 0.00208
TreeTools:::postorder_order(nbal40k) ⚪ NSD -2.48% 2.13 →
2.18, 2.18
TreeTools:::postorder_order(npec40) ⚪ NSD -2.9% 0.0028 →
0.00284, 0.00292
TreeTools:::postorder_order(npec40k) 🟣 ~same 1.32% 3440 →
3430, 3400
TreeTools:::postorder_order(nrnd80) ⚪ NSD -0.89% 0.0045 →
0.00452, 0.00456
TreeTools:::postorder_order(pec40) ⚪ NSD -6.16% 0.00162 →
0.00165, 0.00175
TreeTools:::postorder_order(pec40k) ⚪ NSD 0.79% 0.429 →
0.422, 0.433
TreeTools:::postorder_order(rnd80) ⚪ NSD -0.91% 0.00207 →
0.00207, 0.0021

@github-actions
Copy link

github-actions bot commented Feb 4, 2026

⚠️ This benchmark result is outdated. See the latest comment below.

Performance benchmark results

Call Status Change Time (ms)
as.Splits(bigTrees) ⚪ NSD -2.69% 22.9 →
23.5, 23.5
as.Splits(someTrees) ⚪ NSD 1.95% 11.2 →
11, 10.9
Consensus(forest1k.888, check = FALSE) ⚪ NSD 4.75% 101 →
96.6, 95.4
Consensus(forest201.80, check = FALSE) ⚪ NSD 0.82% 4.07 →
4.06, 4.01
Consensus(forest21.260, 0.5, FALSE) ⚪ NSD -0.74% 1.21 →
1.23, 1.21
Consensus(forest21.260) ⚪ NSD -1.56% 1.19 →
1.22, 1.2
Consensus(forestMaj, 0.5, FALSE) ⚪ NSD -0.39% 2.96 →
2.96, 2.99
DropTip(tr2000, 5) 🟣 ~same -5.95% 18.8 →
19.9, 20.1
DropTip(tr80, 5) ⚪ NSD 0.87% 0.104 →
0.103, 0.103
DropTip(unlen2k, 5) ⚪ NSD 1.79% 0.212 →
0.205, 0.214
DropTip(unlen80, 5) ⚪ NSD -1.18% 0.04 →
0.0401, 0.0409
lapply(bigSplits, as.phylo) 🟣 ~same -1.48% 30.6 →
31, 31.3
lapply(someSplits, as.phylo) ⚪ NSD 1.9% 14.3 →
14, 14
PathLengths(tr2000, full = TRUE) ⚪ NSD -3.18% 18.9 →
19.4, 19.6
PathLengths(tr80, full = TRUE) ⚪ NSD 71.37% 0.0993 →
0.0318, 0.0276
PathLengths(tr80Unif, full = TRUE) ⚪ NSD -3.93% 0.0291 →
0.0323, 0.0298
RootTree(tr2000, 5) ⚪ NSD -0.42% 0.37 →
0.371, 0.372
RootTree(tr80, c("t3", "t36")) ⚪ NSD -0.14% 0.0691 →
0.0682, 0.0701
RootTree(tr80, "t3") ⚪ NSD -1.14% 0.0485 →
0.0486, 0.0495
RootTree(tr80, "t30") ⚪ NSD -1.09% 0.0489 →
0.0491, 0.0497
RootTree(unlen2k, 5) ⚪ NSD 0.94% 0.335 →
0.331, 0.333
RootTree(unlen80, c("t3", "t36")) ⚪ NSD 3.18% 0.0656 →
0.0631, 0.064
RootTree(unlen80, "t3") ⚪ NSD -0.65% 0.0429 →
0.0428, 0.0433
RootTree(unlen80, "t30") ⚪ NSD -0.14% 0.0432 →
0.0427, 0.0436
TreeDist::RobinsonFoulds(forest201.80) ⚪ NSD -4.22% 15.1 →
15.6, 16.4
TreeDist::RobinsonFoulds(forest21.888) ⚪ NSD -0.58% 3.23 →
3.21, 3.26
TreeTools:::path_lengths(tr80$edge, tr80$edge.length, FALSE) ⚪ NSD 0.63% 0.0901 →
0.0904, 0.0888
TreeTools:::postorder_order(bal40) 🟢 Faster! 15.67% 0.00198 →
0.00165, 0.00169
TreeTools:::postorder_order(bal40k) ⚪ NSD 0.28% 0.441 →
0.437, 0.442
TreeTools:::postorder_order(dbal40) ⚪ NSD 0.57% 0.00174 →
0.00172, 0.00174
TreeTools:::postorder_order(dbal40k) ⚪ NSD 0.03% 2.12 →
2.13, 2.08
TreeTools:::postorder_order(dpec40) ⚪ NSD -0.79% 0.00251 →
0.00252, 0.00254
TreeTools:::postorder_order(dpec40k) ⚪ NSD -0.89% 3330 →
3380, 3320
TreeTools:::postorder_order(drnd80) ⚪ NSD -0.76% 0.00396 →
0.00396, 0.00404
TreeTools:::postorder_order(nbal40) ⚪ NSD 0% 0.00208 →
0.00206, 0.00211
TreeTools:::postorder_order(nbal40k) ⚪ NSD 0.87% 2.18 →
2.16, 2.16
TreeTools:::postorder_order(npec40) ⚪ NSD -0.39% 0.00281 →
0.00281, 0.00284
TreeTools:::postorder_order(npec40k) ⚪ NSD -0.05% 3410 →
3430, 3380
TreeTools:::postorder_order(nrnd80) ⚪ NSD -1.78% 0.00451 →
0.00455, 0.00464
TreeTools:::postorder_order(pec40) ⚪ NSD -0.68% 0.00163 →
0.00163, 0.00165
TreeTools:::postorder_order(pec40k) ⚪ NSD 1.82% 0.436 →
0.425, 0.432
TreeTools:::postorder_order(rnd80) ⚪ NSD 0.91% 0.00209 →
0.00203, 0.00213

@github-actions
Copy link

github-actions bot commented Feb 4, 2026

⚠️ This benchmark result is outdated. See the latest comment below.

Performance benchmark results

Call Status Change Time (ms)
as.Splits(bigTrees) 🟢 Faster! 12.01% 26.4 →
23.2, 23.3
as.Splits(someTrees) ⚪ NSD 2.49% 12 →
11.8, 11.4
Consensus(forest1k.888, check = FALSE) ⚪ NSD 4.23% 103 →
99.6, 98.3
Consensus(forest201.80, check = FALSE) ⚪ NSD -0.47% 4.11 →
4.2, 4.09
Consensus(forest21.260, 0.5, FALSE) ⚪ NSD -1.21% 1.21 →
1.22, 1.22
Consensus(forest21.260) ⚪ NSD -2.14% 1.2 →
1.23, 1.22
Consensus(forestMaj, 0.5, FALSE) ⚪ NSD -0.49% 3.06 →
3.07, 3.08
DropTip(tr2000, 5) 🟣 ~same -2.27% 20.7 →
21.3, 21.1
DropTip(tr80, 5) ⚪ NSD 0.27% 0.107 →
0.107, 0.105
DropTip(unlen2k, 5) ⚪ NSD -2.52% 0.209 →
0.22, 0.21
DropTip(unlen80, 5) ⚪ NSD -0.24% 0.0411 →
0.0416, 0.0408
lapply(bigSplits, as.phylo) ⚪ NSD 0.67% 30.9 →
30.8, 30.6
lapply(someSplits, as.phylo) ⚪ NSD 1.1% 14.8 →
14.7, 14.5
PathLengths(tr2000, full = TRUE) ⚪ NSD -0.96% 20.1 →
20.4, 20.1
PathLengths(tr80, full = TRUE) ⚪ NSD 0.74% 0.0282 →
0.0283, 0.0277
PathLengths(tr80Unif, full = TRUE) ⚪ NSD -1.71% 0.0298 →
0.0304, 0.0302
RootTree(tr2000, 5) ⚪ NSD 1.3% 0.397 →
0.38, 0.399
RootTree(tr80, c("t3", "t36")) ⚪ NSD -1.4% 0.0718 →
0.0736, 0.0716
RootTree(tr80, "t3") ⚪ NSD -0.94% 0.0511 →
0.052, 0.0512
RootTree(tr80, "t30") ⚪ NSD -0.53% 0.0515 →
0.0522, 0.0511
RootTree(unlen2k, 5) ⚪ NSD -0.85% 0.334 →
0.338, 0.336
RootTree(unlen80, c("t3", "t36")) ⚪ NSD -0.63% 0.0669 →
0.0682, 0.0656
RootTree(unlen80, "t3") ⚪ NSD -2.59% 0.0441 →
0.046, 0.0442
RootTree(unlen80, "t30") ⚪ NSD -2.33% 0.0446 →
0.0464, 0.0446
TreeDist::RobinsonFoulds(forest201.80) ⚪ NSD -4.6% 15.9 →
16.5, 16.6
TreeDist::RobinsonFoulds(forest21.888) ⚪ NSD -4.93% 3.19 →
3.37, 3.22
TreeTools:::path_lengths(tr80$edge, tr80$edge.length, FALSE) ⚪ NSD 0.31% 0.0916 →
0.0918, 0.0909
TreeTools:::postorder_order(bal40) ⚪ NSD -1.22% 0.00165 →
0.00167, 0.00168
TreeTools:::postorder_order(bal40k) ⚪ NSD -0.02% 0.45 →
0.45, 0.451
TreeTools:::postorder_order(dbal40) ⚪ NSD -1.74% 0.00172 →
0.00175, 0.00175
TreeTools:::postorder_order(dbal40k) ⚪ NSD 0.34% 2.16 →
2.13, 2.17
TreeTools:::postorder_order(dpec40) ⚪ NSD -0.79% 0.00251 →
0.00252, 0.00254
TreeTools:::postorder_order(dpec40k) ⚪ NSD 0.05% 3430 →
3420, 3430
TreeTools:::postorder_order(drnd80) ⚪ NSD 0.75% 0.004 →
0.00397, 0.00396
TreeTools:::postorder_order(nbal40) ⚪ NSD -1.95% 0.00205 →
0.00209, 0.00209
TreeTools:::postorder_order(nbal40k) ⚪ NSD 0.45% 2.2 →
2.19, 2.17
TreeTools:::postorder_order(npec40) ⚪ NSD -0.4% 0.0028 →
0.0028, 0.00282
TreeTools:::postorder_order(npec40k) ⚪ NSD 0.5% 3440 →
3400, 3440
TreeTools:::postorder_order(nrnd80) ⚪ NSD 0.22% 0.00453 →
0.0045, 0.00455
TreeTools:::postorder_order(pec40) ⚪ NSD -0.62% 0.00164 →
0.00163, 0.00167
TreeTools:::postorder_order(pec40k) ⚪ NSD -0.93% 0.431 →
0.433, 0.441
TreeTools:::postorder_order(rnd80) ⚪ NSD 0.48% 0.0021 →
0.00209, 0.00209

Use 'const' instead of 'constexpr' for ct_stack_threshold, ct_max_leaves,
ct_max_leaves_heap, and ct_stack_size to ensure proper external linkage.
This resolves ODR (One Definition Rule) issues when TreeDist or other
packages link against TreeTools headers. constexpr can cause linkage
issues with Rcpp-based packages.

Co-authored-by: ms609 <1695515+ms609@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 4, 2026

@copilot Good start thank you; I had to make some improvements to get this going.

...

Changed constexpr to const for ct_stack_threshold, ct_max_leaves, ct_max_leaves_heap, and ct_stack_size in commit ec33427.

The issue is that constexpr has internal linkage by default in C++, which can cause ODR (One Definition Rule) violations when external packages like TreeDist link against TreeTools headers. Using const ensures proper external linkage and consistent symbol resolution across compilation units.

All tests pass with this change, including the ClusterTable with complex trees test (returns the expected [1] 8 0 8 8 0 8).

@github-actions
Copy link

github-actions bot commented Feb 4, 2026

⚠️ This benchmark result is outdated. See the latest comment below.

Performance benchmark results

Call Status Change Time (ms)
as.Splits(bigTrees) ⚪ NSD -3.82% 24.8 →
23.9, 26.5
as.Splits(someTrees) ⚪ NSD -1.17% 11.5 →
11.3, 11.6
Consensus(forest1k.888, check = FALSE) 🟣 ~same -4.04% 96.8 →
102, 99.6
Consensus(forest201.80, check = FALSE) ⚪ NSD -1.77% 4.01 →
4.08, 4.09
Consensus(forest21.260, 0.5, FALSE) ⚪ NSD -2.03% 1.21 →
1.24, 1.24
Consensus(forest21.260) ⚪ NSD -2.58% 1.2 →
1.23, 1.24
Consensus(forestMaj, 0.5, FALSE) ⚪ NSD -1.19% 2.98 →
3, 3.02
DropTip(tr2000, 5) ⚪ NSD 0.83% 21.1 →
20.8, 21
DropTip(tr80, 5) ⚪ NSD 0.93% 0.106 →
0.105, 0.106
DropTip(unlen2k, 5) ⚪ NSD -1.13% 0.215 →
0.219, 0.217
DropTip(unlen80, 5) ⚪ NSD -0.67% 0.0408 →
0.0407, 0.0414
lapply(bigSplits, as.phylo) ⚪ NSD -0.11% 30.7 →
30.8, 30.7
lapply(someSplits, as.phylo) 🟣 ~same -2.24% 14.3 →
14.5, 14.7
PathLengths(tr2000, full = TRUE) ⚪ NSD 1.22% 20.2 →
19.9, 19.9
PathLengths(tr80, full = TRUE) ⚪ NSD 7.54% 0.0314 →
0.0285, 0.0363
PathLengths(tr80Unif, full = TRUE) ⚪ NSD 6.56% 0.0333 →
0.0304, 0.0339
RootTree(tr2000, 5) ⚪ NSD 0.16% 0.389 →
0.374, 0.397
RootTree(tr80, c("t3", "t36")) ⚪ NSD -0.42% 0.0701 →
0.0699, 0.0708
RootTree(tr80, "t3") ⚪ NSD 1.67% 0.0504 →
0.0493, 0.0498
RootTree(tr80, "t30") ⚪ NSD 1.16% 0.0506 →
0.0491, 0.0506
RootTree(unlen2k, 5) ⚪ NSD -1.99% 0.326 →
0.334, 0.331
RootTree(unlen80, c("t3", "t36")) ⚪ NSD 0.69% 0.0653 →
0.0647, 0.065
RootTree(unlen80, "t3") ⚪ NSD 0.67% 0.0434 →
0.0435, 0.0427
RootTree(unlen80, "t30") ⚪ NSD -0.37% 0.0433 →
0.0438, 0.0432
TreeDist::RobinsonFoulds(forest201.80) ⚪ NSD -3.58% 15 →
15.5, 15.7
TreeDist::RobinsonFoulds(forest21.888) ⚪ NSD -3.7% 3.12 →
3.25, 3.21
TreeTools:::path_lengths(tr80$edge, tr80$edge.length, FALSE) ⚪ NSD 1.63% 0.0931 →
0.0911, 0.0922
TreeTools:::postorder_order(bal40) ⚪ NSD 1.2% 0.00166 →
0.00162, 0.00166
TreeTools:::postorder_order(bal40k) ⚪ NSD -1.57% 0.44 →
0.447, 0.447
TreeTools:::postorder_order(dbal40) ⚪ NSD 1.15% 0.00173 →
0.0017, 0.00174
TreeTools:::postorder_order(dbal40k) ⚪ NSD 0.65% 2.15 →
2.13, 2.14
TreeTools:::postorder_order(dpec40) ⚪ NSD 0.03% 0.00251 →
0.00251, 0.00252
TreeTools:::postorder_order(dpec40k) 🟣 ~same -2.01% 3350 →
3420, 3420
TreeTools:::postorder_order(drnd80) ⚪ NSD 1.25% 0.004 →
0.00397, 0.00393
TreeTools:::postorder_order(nbal40) ⚪ NSD 1.02% 0.00208 →
0.00204, 0.00206
TreeTools:::postorder_order(nbal40k) ⚪ NSD 0.31% 2.18 →
2.17, 2.17
TreeTools:::postorder_order(npec40) ⚪ NSD 0.36% 0.00282 →
0.00281, 0.00281
TreeTools:::postorder_order(npec40k) ⚪ NSD -0.22% 3410 →
3410, 3400
TreeTools:::postorder_order(nrnd80) ⚪ NSD 1.55% 0.00458 →
0.00453, 0.00449
TreeTools:::postorder_order(pec40) ⚪ NSD 0.06% 0.00163 →
0.00163, 0.00163
TreeTools:::postorder_order(pec40k) ⚪ NSD -0.1% 0.439 →
0.44, 0.439
TreeTools:::postorder_order(rnd80) ⚪ NSD 2.38% 0.00209 →
0.00207, 0.00202

@ms609
Copy link
Owner

ms609 commented Feb 5, 2026

@copilot Good start on linux, but windows and macOS still show:

══ Failed tests ════════════════════════════════════════════════════════════════
── Failure ('test-ClusterTable.R:140:3'): ClusterTable with complex trees ──────
Expected as.numeric(RobinsonFoulds(r4)) to equal c(8, 0, 8, 8, 0, 8).
Differences:
actual: 8.0 8.0 8.0 8.0 8.0 8.0
expected: 8.0 0.0 8.0 8.0 0.0 8.0

Changed from 'const' to 'inline constexpr' for ct_stack_threshold,
ct_max_leaves, ct_max_leaves_heap, and ct_stack_size.

In C++17, 'inline constexpr' ensures:
1. Constants can be used in template parameters (std::bitset, std::array)
2. Proper external linkage for dependent packages (TreeDist)
3. No ODR violations - compiler guarantees single definition across TUs
4. Cross-platform consistency (fixes Windows/macOS test failures)

Plain 'const' caused linking issues on Windows/macOS where multiple
definitions could exist across translation units.

Co-authored-by: ms609 <1695515+ms609@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 5, 2026

@copilot Good start on linux, but windows and macOS still show:

══ Failed tests ═════════════════════════════════════��...

Fixed in commit 0237e2c by using inline constexpr instead of const.

The issue was that plain const in a header file can cause multiple definitions across translation units on Windows/macOS. In C++17, inline constexpr ensures:

  • Single definition across all translation units (no ODR violations)
  • Can be used in template parameters (required for std::bitset<ct_stack_threshold + 1>)
  • Proper external linkage for dependent packages

All tests now pass on Linux, and this should resolve the Windows/macOS failures.

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

⚠️ This benchmark result is outdated. See the latest comment below.

Performance benchmark results

Call Status Change Time (ms)
as.Splits(bigTrees) ⚪ NSD -1.51% 23.7 →
22.2, 24.7
as.Splits(someTrees) ⚪ NSD -2.55% 11 →
11.4, 11
Consensus(forest1k.888, check = FALSE) ⚪ NSD 2.75% 97.3 →
94.5, 94.8
Consensus(forest201.80, check = FALSE) ⚪ NSD -0.13% 4.01 →
4.01, 4.02
Consensus(forest21.260, 0.5, FALSE) ⚪ NSD -0.81% 1.2 →
1.21, 1.21
Consensus(forest21.260) ⚪ NSD -1.26% 1.2 →
1.21, 1.21
Consensus(forestMaj, 0.5, FALSE) ⚪ NSD 0.76% 2.96 →
2.95, 2.93
DropTip(tr2000, 5) ⚪ NSD -0.27% 19.9 →
20.1, 19.7
DropTip(tr80, 5) ⚪ NSD 0.69% 0.104 →
0.104, 0.103
DropTip(unlen2k, 5) ⚪ NSD -1.86% 0.205 →
0.212, 0.207
DropTip(unlen80, 5) ⚪ NSD -0.4% 0.0401 →
0.0406, 0.04
lapply(bigSplits, as.phylo) ⚪ NSD -0.71% 30.6 →
31, 30.7
lapply(someSplits, as.phylo) 🟣 ~same -4.53% 13.9 →
14.5, 14.3
PathLengths(tr2000, full = TRUE) ⚪ NSD -0.7% 19.1 →
19.4, 19.1
PathLengths(tr80, full = TRUE) ⚪ NSD 67.15% 0.103 →
0.0321, 0.102
PathLengths(tr80Unif, full = TRUE) ⚪ NSD 5.35% 0.0361 →
0.0338, 0.104
RootTree(tr2000, 5) ⚪ NSD -4.38% 0.375 →
0.39, 0.392
RootTree(tr80, c("t3", "t36")) ⚪ NSD -0.65% 0.07 →
0.0691, 0.0714
RootTree(tr80, "t3") ⚪ NSD -4.14% 0.0493 →
0.0496, 0.0522
RootTree(tr80, "t30") ⚪ NSD -3.24% 0.0496 →
0.0495, 0.0522
RootTree(unlen2k, 5) ⚪ NSD -0.28% 0.328 →
0.326, 0.333
RootTree(unlen80, c("t3", "t36")) ⚪ NSD -1.07% 0.0645 →
0.0646, 0.0657
RootTree(unlen80, "t3") ⚪ NSD -1.65% 0.0431 →
0.0429, 0.0445
RootTree(unlen80, "t30") ⚪ NSD -1.27% 0.0435 →
0.0431, 0.0447
TreeDist::RobinsonFoulds(forest201.80) ⚪ NSD -3.78% 15 →
15.6, 15.5
TreeDist::RobinsonFoulds(forest21.888) ⚪ NSD -3.29% 3.15 →
3.26, 3.26
TreeTools:::path_lengths(tr80$edge, tr80$edge.length, FALSE) ⚪ NSD -0.94% 0.0916 →
0.0945, 0.0909
TreeTools:::postorder_order(bal40) ⚪ NSD 0% 0.00163 →
0.00163, 0.00163
TreeTools:::postorder_order(bal40k) ⚪ NSD -1.14% 0.437 →
0.439, 0.444
TreeTools:::postorder_order(dbal40) ⚪ NSD -0.01% 0.00172 →
0.00172, 0.00172
TreeTools:::postorder_order(dbal40k) ⚪ NSD 1.28% 2.15 →
2.14, 2.08
TreeTools:::postorder_order(dpec40) ⚪ NSD -0.77% 0.00249 →
0.0025, 0.00251
TreeTools:::postorder_order(dpec40k) 🟣 ~same -3.26% 3310 →
3420, 3420
TreeTools:::postorder_order(drnd80) ⚪ NSD 0% 0.00397 →
0.00399, 0.00396
TreeTools:::postorder_order(nbal40) ⚪ NSD -1.02% 0.00205 →
0.00206, 0.00208
TreeTools:::postorder_order(nbal40k) ⚪ NSD 1.17% 2.19 →
2.17, 2.12
TreeTools:::postorder_order(npec40) ⚪ NSD -0.76% 0.00278 →
0.00281, 0.0028
TreeTools:::postorder_order(npec40k) 🟣 ~same -1.75% 3380 →
3450, 3430
TreeTools:::postorder_order(nrnd80) ⚪ NSD 0.42% 0.00453 →
0.00453, 0.0045
TreeTools:::postorder_order(pec40) ⚪ NSD -0.61% 0.00161 →
0.00162, 0.00162
TreeTools:::postorder_order(pec40k) ⚪ NSD -1.16% 0.424 →
0.43, 0.428
TreeTools:::postorder_order(rnd80) ⚪ NSD 0.48% 0.00208 →
0.00208, 0.00206

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

⚠️ This benchmark result is outdated. See the latest comment below.

Performance benchmark results

Call Status Change Time (ms)
as.Splits(bigTrees) ⚪ NSD 2.78% 23.2 →
23, 21.5
as.Splits(someTrees) ⚪ NSD 0.52% 11.9 →
11.8, 11.9
Consensus(forest1k.888, check = FALSE) ⚪ NSD -2.45% 97.2 →
100, 97.5
Consensus(forest201.80, check = FALSE) ⚪ NSD -2.41% 4.17 →
4.17, 4.4
Consensus(forest21.260, 0.5, FALSE) ⚪ NSD -1.76% 1.21 →
1.24, 1.23
Consensus(forest21.260) ⚪ NSD -2.3% 1.21 →
1.25, 1.23
Consensus(forestMaj, 0.5, FALSE) ⚪ NSD -0.93% 3.05 →
3.11, 3.01
DropTip(tr2000, 5) ⚪ NSD 0.22% 20.8 →
20.8, 20.8
DropTip(tr80, 5) ⚪ NSD 2.68% 0.11 →
0.107, 0.106
DropTip(unlen2k, 5) ⚪ NSD 1.27% 0.22 →
0.218, 0.216
DropTip(unlen80, 5) ⚪ NSD 1.2% 0.0418 →
0.0415, 0.0411
lapply(bigSplits, as.phylo) ⚪ NSD -0.26% 31.2 →
31.2, 31.3
lapply(someSplits, as.phylo) ⚪ NSD 0.66% 14.5 →
14.3, 14.4
PathLengths(tr2000, full = TRUE) 🟣 ~same -2.09% 19.8 →
20.3, 20
PathLengths(tr80, full = TRUE) ⚪ NSD 69.02% 0.1 →
0.102, 0.0295
PathLengths(tr80Unif, full = TRUE) ⚪ NSD 67.24% 0.1 →
0.0336, 0.0314
RootTree(tr2000, 5) ⚪ NSD 2.08% 0.398 →
0.376, 0.4
RootTree(tr80, c("t3", "t36")) ⚪ NSD -1.82% 0.0705 →
0.0715, 0.0721
RootTree(tr80, "t3") ⚪ NSD -1.63% 0.0498 →
0.0503, 0.0508
RootTree(tr80, "t30") ⚪ NSD -0.73% 0.0505 →
0.0511, 0.0506
RootTree(unlen2k, 5) ⚪ NSD -1.03% 0.334 →
0.339, 0.335
RootTree(unlen80, c("t3", "t36")) ⚪ NSD -1.95% 0.0654 →
0.0668, 0.0665
RootTree(unlen80, "t3") ⚪ NSD -1.21% 0.0439 →
0.0448, 0.0439
RootTree(unlen80, "t30") ⚪ NSD -1.27% 0.0442 →
0.0451, 0.0442
TreeDist::RobinsonFoulds(forest201.80) ⚪ NSD -2.45% 15.7 →
16.2, 16
TreeDist::RobinsonFoulds(forest21.888) ⚪ NSD -3.99% 3.19 →
3.33, 3.32
TreeTools:::path_lengths(tr80$edge, tr80$edge.length, FALSE) ⚪ NSD -4.74% 0.089 →
0.0944, 0.0923
TreeTools:::postorder_order(bal40) ⚪ NSD -1.87% 0.00166 →
0.00169, 0.00169
TreeTools:::postorder_order(bal40k) ⚪ NSD 1.23% 0.451 →
0.445, 0.445
TreeTools:::postorder_order(dbal40) ⚪ NSD -1.15% 0.00174 →
0.00176, 0.00176
TreeTools:::postorder_order(dbal40k) ⚪ NSD -1.7% 2.12 →
2.16, 2.15
TreeTools:::postorder_order(dpec40) ⚪ NSD -2.83% 0.00247 →
0.00254, 0.00255
TreeTools:::postorder_order(dpec40k) ⚪ NSD -0.1% 3420 →
3420, 3420
TreeTools:::postorder_order(drnd80) ⚪ NSD -0.76% 0.00396 →
0.00398, 0.00399
TreeTools:::postorder_order(nbal40) ⚪ NSD 0.48% 0.0021 →
0.0021, 0.00209
TreeTools:::postorder_order(nbal40k) ⚪ NSD 0.41% 2.21 →
2.2, 2.18
TreeTools:::postorder_order(npec40) ⚪ NSD -1.79% 0.0028 →
0.00285, 0.00284
TreeTools:::postorder_order(npec40k) 🟣 ~same -0.97% 3400 →
3430, 3440
TreeTools:::postorder_order(nrnd80) ⚪ NSD -0.22% 0.00455 →
0.00456, 0.00456
TreeTools:::postorder_order(pec40) ⚪ NSD -2.44% 0.00163 →
0.00169, 0.00166
TreeTools:::postorder_order(pec40k) ⚪ NSD 1.8% 0.44 →
0.43, 0.433
TreeTools:::postorder_order(rnd80) ⚪ NSD -0.01% 0.00207 →
0.00206, 0.00209

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Performance benchmark results

Call Status Change Time (ms)
as.Splits(bigTrees) ⚪ NSD 8.59% 25.2 →
20.6, 24.1
as.Splits(someTrees) ⚪ NSD -2.96% 11.2 →
11.5, 11.7
Consensus(forest1k.888, check = FALSE) ⚪ NSD 0.04% 97.6 →
99.1, 95
Consensus(forest201.80, check = FALSE) ⚪ NSD -0.51% 4.03 →
4.07, 4.04
Consensus(forest21.260, 0.5, FALSE) ⚪ NSD -1.64% 1.21 →
1.24, 1.21
Consensus(forest21.260) ⚪ NSD -2.12% 1.2 →
1.24, 1.21
Consensus(forestMaj, 0.5, FALSE) ⚪ NSD -0.28% 2.98 →
2.98, 2.99
DropTip(tr2000, 5) ⚪ NSD -0.08% 20.4 →
20.3, 20.6
DropTip(tr80, 5) ⚪ NSD 0.8% 0.105 →
0.104, 0.104
DropTip(unlen2k, 5) ⚪ NSD 2.8% 0.214 →
0.207, 0.209
DropTip(unlen80, 5) ⚪ NSD 0.37% 0.0404 →
0.0402, 0.0402
lapply(bigSplits, as.phylo) 🟣 ~same -0.58% 31 →
31.2, 31.1
lapply(someSplits, as.phylo) ⚪ NSD -2.89% 13.9 →
14.1, 14.4
PathLengths(tr2000, full = TRUE) ⚪ NSD 0.1% 19.5 →
19.4, 19.7
PathLengths(tr80, full = TRUE) ⚪ NSD -5.13% 0.0312 →
0.0314, 0.104
PathLengths(tr80Unif, full = TRUE) ⚪ NSD 1.55% 0.0329 →
0.033, 0.031
RootTree(tr2000, 5) ⚪ NSD 0.16% 0.386 →
0.374, 0.393
RootTree(tr80, c("t3", "t36")) ⚪ NSD -0.97% 0.0693 →
0.0698, 0.0702
RootTree(tr80, "t3") ⚪ NSD -0.51% 0.0495 →
0.0494, 0.05
RootTree(tr80, "t30") ⚪ NSD -0.85% 0.0495 →
0.0494, 0.0504
RootTree(unlen2k, 5) ⚪ NSD -1.49% 0.327 →
0.334, 0.329
RootTree(unlen80, c("t3", "t36")) ⚪ NSD -1.46% 0.0638 →
0.0648, 0.0646
RootTree(unlen80, "t3") ⚪ NSD -1.41% 0.0428 →
0.0433, 0.0435
RootTree(unlen80, "t30") ⚪ NSD -1.13% 0.0432 →
0.0437, 0.0435
TreeDist::RobinsonFoulds(forest201.80) ⚪ NSD -6.16% 15.2 →
15.8, 16.3
TreeDist::RobinsonFoulds(forest21.888) ⚪ NSD -3.32% 3.15 →
3.27, 3.24
TreeTools:::path_lengths(tr80$edge, tr80$edge.length, FALSE) ⚪ NSD 1.74% 0.0941 →
0.0934, 0.0917
TreeTools:::postorder_order(bal40) ⚪ NSD -1.84% 0.00163 →
0.00169, 0.00162
TreeTools:::postorder_order(bal40k) ⚪ NSD -0.51% 0.441 →
0.443, 0.444
TreeTools:::postorder_order(dbal40) ⚪ NSD -0.59% 0.0017 →
0.00173, 0.0017
TreeTools:::postorder_order(dbal40k) ⚪ NSD 0.4% 2.13 →
2.1, 2.16
TreeTools:::postorder_order(dpec40) ⚪ NSD 0% 0.00251 →
0.00252, 0.00249
TreeTools:::postorder_order(dpec40k) ⚪ NSD 0.16% 3410 →
3420, 3400
TreeTools:::postorder_order(drnd80) ⚪ NSD 0.48% 0.00398 →
0.00396, 0.00396
TreeTools:::postorder_order(nbal40) ⚪ NSD -0.49% 0.00205 →
0.00209, 0.00203
TreeTools:::postorder_order(nbal40k) 🟣 ~same -2.84% 2.11 →
2.17, 2.17
TreeTools:::postorder_order(npec40) ⚪ NSD -0.36% 0.0028 →
0.00283, 0.00279
TreeTools:::postorder_order(npec40k) ⚪ NSD 0% 3430 →
3430, 3430
TreeTools:::postorder_order(nrnd80) ⚪ NSD -0.65% 0.00448 →
0.00451, 0.00451
TreeTools:::postorder_order(pec40) ⚪ NSD -0.06% 0.00163 →
0.00164, 0.00162
TreeTools:::postorder_order(pec40k) ⚪ NSD 0.18% 0.433 →
0.433, 0.432
TreeTools:::postorder_order(rnd80) ⚪ NSD 0% 0.00206 →
0.00206, 0.00206

@ms609 ms609 merged commit d1103f5 into main Feb 5, 2026
16 of 19 checks passed
@ms609 ms609 deleted the copilot/update-clustertable-logic branch February 5, 2026 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants